/*
                    Misc Structs
*/

#ifndef STRUCTS_H
#define STRUCTS_H

#include "SDL/SDL.h"
#include "Point.h"

#include <string>
#include <vector>

#include <boost/lexical_cast.hpp>

using boost::lexical_cast;
using boost::bad_lexical_cast;

using namespace std;

struct PixelData
{
    PixelData()
    {
        Colour.r = 0;
        Colour.g = 0;
        Colour.b = 0;

        iAlpha = SDL_ALPHA_OPAQUE;
    }

    PixelData(int r, int g, int b, int a)
    {
        Colour.r = r;
        Colour.g = g;
        Colour.b = b;

        iAlpha = a;
    }

    PixelData(SDL_Color NewColour, int a)
    {
        Colour = NewColour;

        iAlpha = a;
    }

    SDL_Color Colour;
    Uint8 iAlpha;
};

struct Seperator
{
       Seperator() { bDragging = false; Image = NULL; Position.x = 0; Position.y = 0; }
       ~Seperator() { SDL_FreeSurface(Image); }

       Point Position;

       SDL_Surface *Image;

       bool bDragging;
};

struct TileInfo
{
     TileInfo() { Position = Point(0,0); TilesheetPosition = Point(0,0); }
     ~TileInfo() {}

     bool operator==(const TileInfo& ComparedInfo)
     {
          if (ComparedInfo.TilesheetPosition.x == this->TilesheetPosition.x)
          {
               if (ComparedInfo.TilesheetPosition.y == this->TilesheetPosition.y)
               {
                    return true;
               }
          }

          return false;
     }

     bool operator!=(const TileInfo& ComparedInfo)
     {
          if (ComparedInfo.TilesheetPosition.x == this->TilesheetPosition.x)
          {
               if (ComparedInfo.TilesheetPosition.y == this->TilesheetPosition.y)
               {
                    return false;
               }
          }

          return true;
     }

     Point Position;
     Point TilesheetPosition;
};

struct Padding
{
    Padding() : iTop(0), iBottom(0), iLeft(0), iRight(0) {}

    Padding(const int& iNewTop, const int& iNewBottom, const int& iNewLeft, const int& iNewRight) : iTop(iNewTop), iBottom(iNewBottom), iLeft(iNewLeft), iRight(iNewRight) {}

    int iTop, iBottom, iLeft, iRight;
};

struct UnicodeString
{
    UnicodeString() {}

	// Construct from an STL string
    UnicodeString(const string& str)
    {
        for (int i = 0; i < str.length(); i++)
        {
            buffer.push_back(static_cast<Uint16>(str.at(i)));
        }
    }

	// Construct from a UnicodeString
    UnicodeString(const UnicodeString& ustr)
    {
        buffer = ustr.buffer;
    }

	// Construct from a Uint16 character
    UnicodeString(const Uint16& u)
    {
        buffer.push_back(u);
    }

    UnicodeString(const vector<Uint16>& v)
    {
        buffer = v;
    }

    ~UnicodeString() { buffer.clear(); carray.clear(); subarray.clear(); }

    UnicodeString& operator=(const UnicodeString& ustr)
    {
        buffer.clear();

        buffer = ustr.buffer;

        return *this;
    }

    UnicodeString& operator=(const string& str)
    {
        buffer.clear();

        for (int i = 0; i < str.length(); i++)
        {
            buffer.push_back(static_cast<Uint16>(str.at(i)));
        }

        return *this;
    }

    UnicodeString& operator=(const Uint16& uchar)
    {
        buffer.clear();

        buffer.push_back(uchar);

        return *this;
    }

    UnicodeString& operator=(const vector<Uint16>& v)
    {
        buffer = v;

        return *this;
    }

    UnicodeString& operator+=(const UnicodeString& ustr)
    {
        for (int i = 0; i < ustr.buffer.size(); i++)
        {
            buffer.push_back(ustr.buffer.at(i));
        }

        return *this;
    }

    UnicodeString& operator+=(const vector<Uint16>& ustr)
    {
        for (int i = 0; i < ustr.size(); i++)
        {
            buffer.push_back(ustr.at(i));
        }

        return *this;
    }

    UnicodeString& operator+=(const Uint16& val)
    {
        buffer.push_back(val);

        return *this;
    }

    UnicodeString& operator+=(const string& str)
    {
        for (int i = 0; i < str.length(); i++)
        {
            buffer.push_back(static_cast<Uint16>(str.at(i)));
        }

        return *this;
    }

    UnicodeString operator+(const UnicodeString& ustr)
    {
        UnicodeString temp = *this;

        temp += ustr;

        return temp;
    }

    UnicodeString operator+(const Uint16& ustr)
    {
        UnicodeString temp = *this;

        temp += ustr;

        return temp;
    }

    UnicodeString operator+(const vector<Uint16>& ustr)
    {
        UnicodeString temp = *this;

        temp += ustr;

        return temp;
    }

    UnicodeString operator+(const string& str)
    {
        UnicodeString temp = *this;

        temp += str;

        return temp;
    }

	// Operator overloads for == (Supports comparisons for UnicodeString and string)
    bool operator==(const UnicodeString& ustr)
    {
        if (buffer == ustr.buffer) { return true; }

        return false;
    }

    bool operator==(const string& str)
    {
        UnicodeString t(str);

        if (t.buffer == buffer) { return true; }

        return false;
    }
	//***********************************************************************

	// Operator overloads for != (Supports comparisons for UnicodeString and string)
    bool operator!=(const UnicodeString& ustr)
    {
        if (buffer == ustr.buffer) { return false; }

        return true;
    }

    bool operator!=(const string& str)
    {
        UnicodeString t(str);

        if (t.buffer == buffer) { return false; }

        return true;
    }
	//***********************************************************************

	// Return the character at index i
    Uint16 operator[](const int& i)
    {
        if (i >=0 && i < buffer.size())
        {
            return buffer.at(i);
        }
        else
        {
            return 0;
        }
    }

	// Return the character at index i
    Uint16 at(const int& i)
    {
        if (i >=0 && i < buffer.size())
        {
            return buffer.at(i);
        }
        else
        {
            return 0;
        }
    }

	// Insert the character i at index pos
    void insert(const int& pos, const Uint16& i)
    {
        buffer.insert(buffer.begin() + pos, 1, i);
    }

	// Get the size of the UnicodeString
    int size()
    {
        return buffer.size();
    }

	// Same as size()
    int length()
    {
        return buffer.size();
    }

	// Erase num characters starting at index pos
    void erase(const int& pos, const int& num)
    {
        if (pos >= 0 && (pos + num) <= buffer.size())
        {
            buffer.erase(buffer.begin() + pos, buffer.begin() + (pos + num));
        }
    }

	// Erase characters from pos to the end of the UnicodeString
    void erase(const int& pos)
    {
        if (pos >= 0 && pos < buffer.size())
        {
            buffer.erase(buffer.begin() + pos);
        }
    }

    // Return a NULL terminated C Array
    Uint16* ToCArray()
    {
        carray = buffer;

        // Make it NULL terminated
        carray.push_back(0);

        return &carray[0];
    }

	// Return a NULL terminated C Array starting at i and length characters long
    Uint16* SubArray(const int& i, const int& length)
    {
        subarray = vector<Uint16>(buffer.begin() + i, buffer.begin() + (i + length));

        subarray.push_back(0);

        return &subarray[0];
    }

	// Return a NULL terminated C Array starting at i and length characters long
    Uint16* substr(const int& i, const int& length)
    {
        return SubArray(i, length);
    }

	// Return a Uint16 vector starting at i and length characters long
    vector<Uint16> SubVector(const int& i, int length = -1)
    {
        if (length == -1) { length = buffer.size() - i; }

        vector<Uint16> ret(buffer.begin() + i, buffer.begin() + (i + length));

        return ret;
    }

	// Return the UnicodeString converted to an ASCII string
    string ToString()
    {
        string str("");

        for (int i = 0; i < buffer.size(); i++)
        {
            str += static_cast<char>(buffer.at(i));
        }

        return str;
    }

	/* Return a string literal representation of the UnicodeString

	Example:

	If the UnicodeString contains the characters 45 and 78 this will return "45,78,"

	*/
    string ToStringLiteral()
    {
        string str("");

        for (int i = 0; i < buffer.size(); i++)
        {
            str += lexical_cast<string>(buffer.at(i));
            str += ",";
        }

        return str;
    }

	//**********************************************************************

	// Add characters parsed from a string literal that has been generated with UnicodeString.ToStringLiteral()
    void AddStringLiteral(const string& _str)
    {
        string tstr("");

        string str = _str;

        for (int i = str.find(","); i != string::npos; )
        {
            tstr = str.substr(0, i);

            buffer.push_back(lexical_cast<Uint16>(tstr));

            str.erase(str.begin(), str.begin() + (i + 1));

            i = str.find(",");
        }
    }

	// Set the UnicodeString from a string literal that has been generated with UnicodeString.ToStringLiteral()
    void SetToStringLiteral(const string& str)
    {
        buffer.clear();

        AddStringLiteral(str);
    }

	// Replace all characters with c
    void ReplaceFill(const char& c)
    {
        int iNum = buffer.size();

        buffer.clear();

        for (int i = 0; i < iNum; i++)
        {
            buffer.push_back(static_cast<Uint16>(c));
        }
    }

	// Replace all characters with u
    void ReplaceFill(const Uint16& u)
    {
        int iNum = buffer.size();

        buffer.clear();

        for (int i = 0; i < iNum; i++)
        {
            buffer.push_back(u);
        }
    }

	// Internal Uint16 character buffer
    vector<Uint16> buffer;

    private:
		// Internal C Array buffer
        vector<Uint16> carray;

		// Internal substr C Array buffer
        vector<Uint16> subarray;
};

#endif
